// Filename: mouseWatcher.I
// Created by:  drose (12Mar02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University.  All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license.  You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::has_mouse
//       Access: Published
//  Description: Returns true if the mouse is anywhere within the
//               window, false otherwise.  Also see is_mouse_open().
////////////////////////////////////////////////////////////////////
INLINE bool MouseWatcher::
has_mouse() const {
  return _has_mouse;
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::is_mouse_open
//       Access: Published
//  Description: Returns true if the mouse is within the window and
//               not over some particular MouseWatcherRegion that is
//               marked to suppress mouse events; that is, that the
//               mouse is in open space within the window.
////////////////////////////////////////////////////////////////////
INLINE bool MouseWatcher::
is_mouse_open() const {
  return _has_mouse && (_internal_suppress & MouseWatcherRegion::SF_mouse_position) == 0;
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::get_mouse
//       Access: Published
//  Description: It is only valid to call this if has_mouse() returns
//               true.  If so, this returns the current position of
//               the mouse within the window.
////////////////////////////////////////////////////////////////////
INLINE const LPoint2 &MouseWatcher::
get_mouse() const {
#ifndef NDEBUG
  static LPoint2 bogus_mouse(0.0f, 0.0f);
  nassertr(_has_mouse, bogus_mouse);
#endif
  return _mouse;
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::get_mouse_x
//       Access: Published
//  Description: It is only valid to call this if has_mouse() returns
//               true.  If so, this returns the current X position of
//               the mouse within the window.
////////////////////////////////////////////////////////////////////
INLINE PN_stdfloat MouseWatcher::
get_mouse_x() const {
  nassertr(_has_mouse, 0.0f);
  return _mouse[0];
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::get_mouse_y
//       Access: Published
//  Description: It is only valid to call this if has_mouse() returns
//               true.  If so, this returns the current Y position of
//               the mouse within the window.
////////////////////////////////////////////////////////////////////
INLINE PN_stdfloat MouseWatcher::
get_mouse_y() const {
  nassertr(_has_mouse, 0.0f);
  return _mouse[1];
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::set_frame
//       Access: Published
//  Description: Sets the frame of the MouseWatcher.  See the next
//               flavor of this method for a more verbose explanation.
////////////////////////////////////////////////////////////////////
INLINE void MouseWatcher::
set_frame(PN_stdfloat left, PN_stdfloat right, PN_stdfloat bottom, PN_stdfloat top) {
  set_frame(LVecBase4(left, right, bottom, top));
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::set_frame
//       Access: Published
//  Description: Sets the frame of the MouseWatcher.  This determines
//               the coordinate space in which the MouseWatcherRegions
//               should be expected to live.  Normally, this is left
//               at -1, 1, -1, 1, which is the default setting, and
//               matches the mouse coordinate range.
//
//               Whatever values you specify here indicate the shape
//               of the full screen, and the MouseWatcherRegions will
//               be given in coordinate space matching it.  For
//               instance, if you specify (0, 1, 0, 1), then a
//               MouseWatcherRegion with the frame (0, 1, 0, .5) will
//               cover the lower half of the screen.
////////////////////////////////////////////////////////////////////
INLINE void MouseWatcher::
set_frame(const LVecBase4 &frame) {
  _frame = frame;
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::get_frame
//       Access: Published
//  Description: Returns the frame of the MouseWatcher.  See
//               set_frame().
////////////////////////////////////////////////////////////////////
INLINE const LVecBase4 &MouseWatcher::
get_frame() const {
  return _frame;
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::is_over_region
//       Access: Published
//  Description: Returns true if the mouse is over any rectangular
//               region, false otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool MouseWatcher::
is_over_region() const {
  return get_over_region() != (MouseWatcherRegion *)NULL;
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::is_over_region
//       Access: Published
//  Description: Returns true if the mouse is over any rectangular
//               region, false otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool MouseWatcher::
is_over_region(PN_stdfloat x, PN_stdfloat y) const {
  return get_over_region(x, y) != (MouseWatcherRegion *)NULL;
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::is_over_region
//       Access: Published
//  Description: Returns true if the mouse is over any rectangular
//               region, false otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool MouseWatcher::
is_over_region(const LPoint2 &pos) const {
  return get_over_region(pos) != (MouseWatcherRegion *)NULL;
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::get_over_region
//       Access: Published
//  Description: Returns the smallest region the mouse is currently
//               over, or NULL if it is over no region.
////////////////////////////////////////////////////////////////////
INLINE MouseWatcherRegion *MouseWatcher::
get_over_region() const {
  return _preferred_region;
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::get_over_region
//       Access: Published
//  Description: Returns the smallest region the indicated point is
//               over, or NULL if it is over no region.
////////////////////////////////////////////////////////////////////
INLINE MouseWatcherRegion *MouseWatcher::
get_over_region(PN_stdfloat x, PN_stdfloat y) const {
  return get_over_region(LPoint2(x, y));
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::is_button_down
//       Access: Published
//  Description: Returns true if the indicated button is currently
//               being held down, false otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool MouseWatcher::
is_button_down(ButtonHandle button) const {
  return _inactivity_state != IS_inactive && _current_buttons_down.get_bit(button.get_index());
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::set_button_down_pattern
//       Access: Published
//  Description: Sets the pattern string that indicates how the event
//               names are generated when a button is depressed.  This
//               is a string that may contain any of the following:
//
//                  %r  - the name of the region the mouse is over
//                  %b  - the name of the button pressed.
//
//               The event name will be based on the in_pattern
//               string specified here, with all occurrences of the
//               above strings replaced with the corresponding values.
////////////////////////////////////////////////////////////////////
INLINE void MouseWatcher::
set_button_down_pattern(const string &pattern) {
  _button_down_pattern = pattern;
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::get_button_down_pattern
//       Access: Published
//  Description: Returns the string that indicates how event names are
//               generated when a button is depressed.  See
//               set_button_down_pattern().
////////////////////////////////////////////////////////////////////
INLINE const string &MouseWatcher::
get_button_down_pattern() const {
  return _button_down_pattern;
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::set_button_up_pattern
//       Access: Published
//  Description: Sets the pattern string that indicates how the event
//               names are generated when a button is released.  See
//               set_button_down_pattern().
////////////////////////////////////////////////////////////////////
INLINE void MouseWatcher::
set_button_up_pattern(const string &pattern) {
  _button_up_pattern = pattern;
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::get_button_up_pattern
//       Access: Published
//  Description: Returns the string that indicates how event names are
//               generated when a button is released.  See
//               set_button_down_pattern().
////////////////////////////////////////////////////////////////////
INLINE const string &MouseWatcher::
get_button_up_pattern() const {
  return _button_up_pattern;
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::set_button_repeat_pattern
//       Access: Published
//  Description: Sets the pattern string that indicates how the event
//               names are generated when a button is continuously
//               held and generates keyrepeat "down" events.  This is
//               a string that may contain any of the following:
//
//                  %r  - the name of the region the mouse is over
//                  %b  - the name of the button pressed.
//
//               The event name will be based on the in_pattern
//               string specified here, with all occurrences of the
//               above strings replaced with the corresponding values.
////////////////////////////////////////////////////////////////////
INLINE void MouseWatcher::
set_button_repeat_pattern(const string &pattern) {
  _button_repeat_pattern = pattern;
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::get_button_repeat_pattern
//       Access: Published
//  Description: Returns the string that indicates how event names are
//               names are generated when a button is continuously
//               held and generates keyrepeat "down" events.  See
//               set_button_repeat_pattern().
////////////////////////////////////////////////////////////////////
INLINE const string &MouseWatcher::
get_button_repeat_pattern() const {
  return _button_repeat_pattern;
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::set_enter_pattern
//       Access: Published
//  Description: Sets the pattern string that indicates how the event
//               names are generated when the mouse enters a region.
//               This is different from within_pattern, in that a
//               mouse is only "entered" in the topmost region at a
//               given time, while it might be "within" multiple
//               nested regions.
////////////////////////////////////////////////////////////////////
INLINE void MouseWatcher::
set_enter_pattern(const string &pattern) {
  _enter_pattern = pattern;
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::get_enter_pattern
//       Access: Published
//  Description: Returns the string that indicates how event names are
//               generated when the mouse enters a region.  This is
//               different from within_pattern, in that a mouse is
//               only "entered" in the topmost region at a given time,
//               while it might be "within" multiple nested regions.
////////////////////////////////////////////////////////////////////
INLINE const string &MouseWatcher::
get_enter_pattern() const {
  return _enter_pattern;
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::set_leave_pattern
//       Access: Published
//  Description: Sets the pattern string that indicates how the event
//               names are generated when the mouse leaves a region.
//               This is different from without_pattern, in that a
//               mouse is only "entered" in the topmost region at a
//               given time, while it might be "within" multiple
//               nested regions.
////////////////////////////////////////////////////////////////////
INLINE void MouseWatcher::
set_leave_pattern(const string &pattern) {
  _leave_pattern = pattern;
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::get_leave_pattern
//       Access: Published
//  Description: Returns the string that indicates how event names are
//               generated when the mouse leaves a region.  This is
//               different from without_pattern, in that a mouse is
//               only "entered" in the topmost region at a given time,
//               while it might be "within" multiple nested regions.
////////////////////////////////////////////////////////////////////
INLINE const string &MouseWatcher::
get_leave_pattern() const {
  return _leave_pattern;
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::set_within_pattern
//       Access: Published
//  Description: Sets the pattern string that indicates how the event
//               names are generated when the mouse wanders over a
//               region.  This is different from enter_pattern, in
//               that a mouse is only "entered" in the topmost region
//               at a given time, while it might be "within" multiple
//               nested regions.
////////////////////////////////////////////////////////////////////
INLINE void MouseWatcher::
set_within_pattern(const string &pattern) {
  _within_pattern = pattern;
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::get_within_pattern
//       Access: Published
//  Description: Returns the string that indicates how event names are
//               generated when the mouse wanders over a region.  This
//               is different from enter_pattern, in that a mouse is
//               only "entered" in the topmost region at a given time,
//               while it might be "within" multiple nested regions.
////////////////////////////////////////////////////////////////////
INLINE const string &MouseWatcher::
get_within_pattern() const {
  return _within_pattern;
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::set_without_pattern
//       Access: Published
//  Description: Sets the pattern string that indicates how the event
//               names are generated when the mouse wanders out of a
//               region.  This is different from leave_pattern, in
//               that a mouse is only "entered" in the topmost region
//               at a given time, while it might be "within" multiple
//               nested regions.
////////////////////////////////////////////////////////////////////
INLINE void MouseWatcher::
set_without_pattern(const string &pattern) {
  _without_pattern = pattern;
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::get_without_pattern
//       Access: Published
//  Description: Returns the string that indicates how event names are
//               generated when the mouse wanders out of a region.
//               This is different from leave_pattern, in that a mouse
//               is only "entered" in the topmost region at a given
//               time, while it might be "within" multiple nested
//               regions.
////////////////////////////////////////////////////////////////////
INLINE const string &MouseWatcher::
get_without_pattern() const {
  return _without_pattern;
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::set_geometry
//       Access: Published
//  Description: Sets the node that will be transformed each frame by
//               the mouse's coordinates.  It will also be hidden when
//               the mouse goes outside the window.  This can be used
//               to implement a software mouse pointer for when a
//               hardware (or system) mouse pointer is unavailable.
////////////////////////////////////////////////////////////////////
INLINE void MouseWatcher::
set_geometry(PandaNode *node) {
  _geometry = node;
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::has_geometry
//       Access: Published
//  Description: Returns true if a software mouse pointer has been
//               setup via set_geometry(), or false otherwise.  See
//               set_geometry().
////////////////////////////////////////////////////////////////////
INLINE bool MouseWatcher::
has_geometry() const {
  return !_geometry.is_null();
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::get_geometry
//       Access: Published
//  Description: Returns the node that has been set as the software
//               mouse pointer, or NULL if no node has been set.  See
//               has_geometry() and set_geometry().
////////////////////////////////////////////////////////////////////
INLINE PandaNode *MouseWatcher::
get_geometry() const {
  return _geometry;
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::clear_geometry
//       Access: Published
//  Description: Stops the use of the software cursor set up via
//               set_geometry().
////////////////////////////////////////////////////////////////////
INLINE void MouseWatcher::
clear_geometry() {
  _geometry.clear();
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::set_extra_handler
//       Access: Published
//  Description: As an optimization for the C++ Gui, an extra handler
//               can be registered with a mouseWatcher so that events
//               can be dealt with much sooner.
////////////////////////////////////////////////////////////////////
INLINE void MouseWatcher::
set_extra_handler(EventHandler *eh) {
  _eh = eh;
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::get_extra_handler
//       Access: Published
//  Description: As an optimization for the C++ Gui, an extra handler
//               can be registered with a mouseWatcher so that events
//               can be dealt with much sooner.
////////////////////////////////////////////////////////////////////
INLINE EventHandler *MouseWatcher::
get_extra_handler() const {
  return _eh;
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::set_modifier_buttons
//       Access: Public
//  Description: Sets the buttons that should be monitored as modifier
//               buttons for generating events to the
//               MouseWatcherRegions.
////////////////////////////////////////////////////////////////////
INLINE void MouseWatcher::
set_modifier_buttons(const ModifierButtons &mods) {
  _mods = mods;
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::get_modifier_buttons
//       Access: Published
//  Description: Returns the set of buttons that are being monitored
//               as modifier buttons, as well as their current state.
////////////////////////////////////////////////////////////////////
INLINE ModifierButtons MouseWatcher::
get_modifier_buttons() const {
  return _mods;
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::set_display_region
//       Access: Published
//  Description: Constrains the MouseWatcher to watching the mouse
//               within a particular indicated region of the screen.
//               DataNodes parented under the MouseWatcher will
//               observe the mouse and keyboard events only when the
//               mouse is within the indicated region, and the
//               observed range will be from -1 .. 1 across the
//               region.
//
//               Do not delete the DisplayRegion while it is owned by
//               the MouseWatcher.
////////////////////////////////////////////////////////////////////
INLINE void MouseWatcher::
set_display_region(DisplayRegion *dr) {
  _display_region = dr;
  _button_down_display_region = NULL;
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::clear_display_region
//       Access: Published
//  Description: Removes the display region constraint from the
//               MouseWatcher, and restores it to the default behavior
//               of watching the whole window.
////////////////////////////////////////////////////////////////////
INLINE void MouseWatcher::
clear_display_region() {
  _display_region = NULL;
  _button_down_display_region = NULL;
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::get_display_region
//       Access: Published
//  Description: Returns the display region the MouseWatcher is
//               constrained to by set_display_region(), or NULL if it
//               is not constrained.
////////////////////////////////////////////////////////////////////
INLINE DisplayRegion *MouseWatcher::
get_display_region() const {
  return _display_region;
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::has_display_region
//       Access: Published
//  Description: Returns true if the MouseWatcher has been constrained
//               to a particular region of the screen via
//               set_display_region(), or false otherwise.  If this
//               returns true, get_display_region() may be used to
//               return the particular region.
////////////////////////////////////////////////////////////////////
INLINE bool MouseWatcher::
has_display_region() const {
  return (_display_region != (DisplayRegion *)NULL);
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::set_inactivity_timeout
//       Access: Published
//  Description: Sets an inactivity timeout on the mouse activity.
//               When this timeout (in seconds) is exceeded with no
//               keyboard or mouse activity, all currently-held
//               buttons are automatically released.  This is intended
//               to help protect against people who inadvertently (or
//               intentionally) leave a keyboard key stuck down and
//               then wander away from the keyboard.
//
//               Also, when this timeout expires, the event specified
//               by set_inactivity_timeout_event() will be generated.
////////////////////////////////////////////////////////////////////
INLINE void MouseWatcher::
set_inactivity_timeout(double timeout) {
  _has_inactivity_timeout = true;
  _inactivity_timeout = timeout;
  note_activity();
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::has_inactivity_timeout
//       Access: Published
//  Description: Returns true if an inactivity timeout has been set,
//               false otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool MouseWatcher::
has_inactivity_timeout() const {
  return _has_inactivity_timeout;
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::get_inactivity_timeout
//       Access: Published
//  Description: Returns the inactivity timeout that has been set.
//               It is an error to call this if
//               has_inactivity_timeout() returns false.
////////////////////////////////////////////////////////////////////
INLINE double MouseWatcher::
get_inactivity_timeout() const {
  nassertr(_has_inactivity_timeout, 0.0);
  return _inactivity_timeout;
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::clear_inactivity_timeout
//       Access: Published
//  Description: Removes the inactivity timeout and restores the
//               MouseWatcher to its default behavior of allowing a
//               key to be held indefinitely.
////////////////////////////////////////////////////////////////////
INLINE void MouseWatcher::
clear_inactivity_timeout() {
  _has_inactivity_timeout = false;
  _inactivity_timeout = 0.0;
  note_activity();
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::set_inactivity_timeout_event
//       Access: Published
//  Description: Specifies the event string that will be generated
//               when the inactivity timeout counter expires.  See
//               set_inactivity_timeout().
////////////////////////////////////////////////////////////////////
INLINE void MouseWatcher::
set_inactivity_timeout_event(const string &event) {
  _inactivity_timeout_event = event;
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::get_inactivity_timeout_event
//       Access: Published
//  Description: Returns the event string that will be generated
//               when the inactivity timeout counter expires.  See
//               set_inactivity_timeout().
////////////////////////////////////////////////////////////////////
INLINE const string &MouseWatcher::
get_inactivity_timeout_event() const {
  return _inactivity_timeout_event;
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::within_region
//       Access: Protected
//  Description: Called internally to indicate the mouse pointer has
//               moved within the indicated region's boundaries.
////////////////////////////////////////////////////////////////////
INLINE void MouseWatcher::
within_region(MouseWatcherRegion *region, const MouseWatcherParameter &param) {
  region->within_region(param);
  throw_event_pattern(_within_pattern, region, ButtonHandle::none());
  if (_enter_multiple) {
    enter_region(region, param);
  }
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::without_region
//       Access: Protected
//  Description: Called internally to indicate the mouse pointer has
//               moved outside of the indicated region's boundaries.
////////////////////////////////////////////////////////////////////
INLINE void MouseWatcher::
without_region(MouseWatcherRegion *region, const MouseWatcherParameter &param) {
  if (_enter_multiple) {
    exit_region(region, param);
  }
  region->without_region(param);
  throw_event_pattern(_without_pattern, region, ButtonHandle::none());
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::clear_trail_log
//       Access: Published
//  Description: Clears the mouse trail log.  This does not prevent
//               further accumulation of the log given future events.
////////////////////////////////////////////////////////////////////
INLINE void MouseWatcher::
clear_trail_log() {
  _trail_log->clear();
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::get_trail_log
//       Access: Published
//  Description: Obtain the mouse trail log.  This is a PointerEventList.
//               Does not make a copy, therefore, this PointerEventList
//               will be updated each time process_events gets called.
//
//               To use trail logging, you need to enable the
//               generation of pointer events in the
//               GraphicsWindowInputDevice and set the trail log
//               duration in the MouseWatcher. Otherwise, the
//               trail log will be empty.
////////////////////////////////////////////////////////////////////
INLINE CPT(PointerEventList) MouseWatcher::
get_trail_log() const {
  return _trail_log;
}

////////////////////////////////////////////////////////////////////
//     Function: MouseWatcher::num_trail_recent
//       Access: Published
//  Description: This counter indicates how many events were added
//               to the trail log this frame.  The trail log is
//               updated once per frame, during the process_events
//               operation.  
////////////////////////////////////////////////////////////////////
INLINE int MouseWatcher::
num_trail_recent() const {
  return _num_trail_recent;
}
